﻿
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net.Http;
using System.Text;
using System.Threading.Tasks;
using mBook.Utils;
using mBook.Models;
using Windows.Storage;
using System.Net;
using System.IO;
using System.Diagnostics;
using mBook.ViewModels;
using Windows.UI.Xaml;
using Windows.ApplicationModel.Core;
using Windows.Networking.BackgroundTransfer;
using System.Threading;

namespace mBook.DataManager
{
    class DataService
    {

        private List<DownloadOperation> activeDownloads;
        private List<String> listMediaID_downloading;
        private CancellationTokenSource cts;
        private bool isDiscoverActiveDownloaded = false;

        public static DataService instance = null;

        public static DataService GetInstance()
        {
            if (instance == null)
            {
                instance = new DataService();
                
                return instance;
            }
            return instance;
        }

        public  DataService()
        {
            cts = new CancellationTokenSource();
            listMediaID_downloading = new List<String>();
            
        }

        private String downloadingEbookID;



        /******* get list Ebook ******/
        public async Task<EbookList> GetListEbookByTopDownload()
        {
            try
            {                
                String link = Constants.URL_HOST + Constants.URL_GET_TOP_PAID;
                EbookList ebookList = null;
                ebookList= await RESTfulService.HTTPGetRequest(link, typeof(EbookList)) as EbookList;

                return ebookList;
            }
            catch (Exception e)
            {
                throw new Exception("could not connect to server");              
            }
        }


        public async Task<CategoryList> GetListCategories()
        {
            try
            {
                String link = Constants.URL_HOST + Constants.URL_GET_CATEGORIES;
                CategoryList ebookList = null;
                ebookList = await RESTfulService.HTTPGetRequest(link, typeof(CategoryList)) as CategoryList;

                return ebookList;
            }
            catch (Exception e)
            {
                throw new Exception("could not connect to server");

            }
        }

        /********** Download *************/
        public async Task<String> GetUrlToDownload(Ebook ebook)
        {
            String link = Constants.URL_HOST + Constants.URL_GET_DOWNLOAD_FROM_PURCHASED;
            
            String postData = "{\"accessToken\":\"" + Constants.ACCESS_TOKEN + "\", \"deviceId\": \"" + Constants.IMEL + "\",\"mediaId\": \"" + ebook.MediaId + "\"}";

            InFoMessagePurchasedFromDownload inFoObject = await RESTfulService.HTTPPostRequest(link,postData ,typeof (InFoMessagePurchasedFromDownload)) as InFoMessagePurchasedFromDownload;
            if (inFoObject.Ebook != null)
            {
                ebook.Password = inFoObject.Ebook.Password;
                return inFoObject.Ebook.EncryptUrl;
            }
            return null;
        }



        public async Task<bool> Download(Ebook ebook)
        {
             StorageFolder storeFolder;
            
            storeFolder = await ApplicationData.Current.LocalFolder.CreateFolderAsync(Constants.FOLDER_SAVE_FILE, CreationCollisionOption.OpenIfExists);
            
            StorageFile newfile = await storeFolder.CreateFileAsync(ebook.Name + "." + ebook.FileType, CreationCollisionOption.ReplaceExisting);

            ebook.FilePath = Constants.FOLDER_SAVE_FILE + "\\" + ebook.Name + "." + ebook.FileType;
            try
            {
                String linkEbook = await GetUrlToDownload(ebook);

                Uri source;
                if (!Uri.TryCreate(linkEbook, UriKind.Absolute, out source))
                {
                    throw new Exception("Link to download not exist");
                    
                }

                if (!isDiscoverActiveDownloaded)
                {
                    await DiscoverActiveDownloadsAsync();
                    isDiscoverActiveDownloaded = true;
                }

                BackgroundDownloader downloader = new BackgroundDownloader();
                DownloadOperation download = downloader.CreateDownload(source, newfile);


                listMediaID_downloading.Add(ebook.MediaId);
                // Attach progress and completion handlers.
                await HandleDownloadAsync(download, true);
            }
            catch (Exception e)
            {
                throw new Exception("could not connect to server");
            }

            return true;
        }

        // Enumerate the downloads that were going on in the background while the app was closed.
        private async Task DiscoverActiveDownloadsAsync()
        {
            activeDownloads = new List<DownloadOperation>();

            IReadOnlyList<DownloadOperation> downloads = null;
            try
            {
                downloads = await BackgroundDownloader.GetCurrentDownloadsAsync();
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }

            

            if (downloads.Count > 0)
            {
                List<Task> tasks = new List<Task>();
                foreach (DownloadOperation download in downloads)
                {
                   

                    // Attach progress and completion handlers.
                    tasks.Add(HandleDownloadAsync(download, false));
                }

                // Don't await HandleDownloadAsync() in the foreach loop since we would attach to the second
                // download only when the first one completed; attach to the third download when the second one
                // completes etc. We want to attach to all downloads immediately.
                // If there are actions that need to be taken once downloads complete, await tasks here, outside
                // the loop.
                await Task.WhenAll(tasks);
            }
        }

        // Note that this event is invoked on a background thread, so we cannot access the UI directly.
        private void DownloadProgress(DownloadOperation download)
        {
            

            double percent = 0;
            if (download.Progress.TotalBytesToReceive > 0)
            {
                percent = download.Progress.BytesReceived * 100 / download.Progress.TotalBytesToReceive;
            }

            CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
            {
                int index = activeDownloads.IndexOf(download);
                if (index >= 0)
                {
                    EbookViewModel dataEbook = ManagerDataViewModel.GetItem(listMediaID_downloading.ElementAt(index));
                    if (dataEbook != null)
                        dataEbook.PercentDownloading = percent.ToString();
                }
            });

            
        }

        private async Task HandleDownloadAsync(DownloadOperation download, bool start)
        {
            try
            {
                

                // Store the download so we can pause/resume.
                activeDownloads.Add(download);

                Progress<DownloadOperation> progressCallback = new Progress<DownloadOperation>(DownloadProgress);
                if (start)
                {
                    // Start the download and attach a progress handler.
                    await download.StartAsync().AsTask(cts.Token, progressCallback);
                }
                else
                {
                    // The download was already running when the application started, re-attach the progress handler.
                    await download.AttachAsync().AsTask(cts.Token, progressCallback);
                }

                ResponseInformation response = download.GetResponseInformation();

               
            }
            catch (TaskCanceledException)
            {
                throw new Exception(download.Guid.ToString());
            }
            catch (Exception ex)
            {
                throw new Exception(ex.Message);
            }
            finally
            {
                int index = activeDownloads.IndexOf(download);
                activeDownloads.Remove(download);
                listMediaID_downloading.RemoveAt(index);
            }
        }


        //currently just download 1 item in a time, stop download a item -> stop all process
        public void StopDownload(String ebookID)
        {
            

            cts.Cancel();
            cts.Dispose();

            // Re-create the CancellationTokenSource and activeDownloads for future downloads.
            listMediaID_downloading.Clear();
            cts = new CancellationTokenSource();
            activeDownloads = new List<DownloadOperation>();
        }

        public void PauseDownload(String ebookID)
        {
            

            foreach (DownloadOperation download in activeDownloads)
            {
                if (download.Progress.Status == BackgroundTransferStatus.Running)
                {
                    download.Pause();
                    
                }
                else
                {
                    
                }
            }
        }

        //long getFileSizeFromString(String strFileSize)
        //{
        //    String[] arrString = strFileSize.Split(' ');
        //    if (arrString.Count() == 2)
        //    {
        //        long fileSize = 0;
        //        if (arrString[1].Contains("K"))
        //        {
        //            fileSize = (long) (float.Parse(arrString[0]) * 1024);
        //        }
        //        else if (arrString[1].Contains("M"))
        //        {
        //            fileSize = (long) (float.Parse(arrString[0]) * 1024 * 1024);
        //        }
        //        else if (arrString[1].Contains("G"))
        //        {
        //            fileSize = (long)(float.Parse(arrString[0]) * 1024 * 1024 * 1024);
        //        }
        //        else
        //        {
        //            fileSize = (long)float.Parse(arrString[0]);
        //        }
        //        return fileSize;
        //    }

        //    return 0;
        //}

        //void ps_Progress(object sender, int Progress, long Transfered, long Length, StorageFile file)
        //{

        //    CoreApplication.MainView.CoreWindow.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () =>
        //    {
                
        //        DataEbook dataEbook = DataViewModel.GetItem(downloadingEbookID);
        //        dataEbook.PercentDownloading = Progress.ToString();
        //    });
        //}


    }
}
